/**
* \file DGVSurfacePlotVTK.h
*
* \brief This file defines a class for display Surface Plots using VTK.
* \author Shekhar S. Chandra, 2008-2009
*
* This file is part of DGV Library.
*
* DGV is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DGV is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with DGV.  If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef DGVSURFACEPLOTVTK_H
#define DGVSURFACEPLOTVTK_H

#include <QtGui/QtGui>

#include "QVTKWidget.h"
#include "vtkSmartPointer.h"
#include "vtkImageData.h"
#include "vtkImageDataGeometryFilter.h"
#include "vtkImageLogarithmicScale.h"
#include "vtkWarpScalar.h"
#include "vtkCubeAxesActor2D.h" //For axes
#include "vtkPolyDataNormals.h"
#include "vtkPolyDataMapper.h"
#include "vtkLODActor.h"
//#include "vtkActor.h"
#include "vtkRenderer.h"
#include "vtkRenderWindow.h"

#include "DGVAliases.h"
#include "DGVBlitzArrayCasterVTK.h"
#include "DGVConsole.h"

#include "ui/ThresholdForm.h"

typedef vtkSmartPointer<vtkImageData> PlotData; //!< Smart Pointers for Automated Garbage Collection
typedef vtkSmartPointer<vtkImageLogarithmicScale> PlotLogScale; //!< Smart Pointers for Automated Garbage Collection
typedef vtkSmartPointer<vtkImageDataGeometryFilter> PlotGeometry; //!< Smart Pointers for Automated Garbage Collection
typedef vtkSmartPointer<vtkWarpScalar> PlotWarp; //!< Smart Pointers for Automated Garbage Collection
typedef vtkSmartPointer<vtkPolyDataNormals> PlotNorms; //!< Smart Pointers for Automated Garbage Collection
typedef vtkSmartPointer<vtkPolyDataMapper> PlotMapper; //!< Smart Pointers for Automated Garbage Collection
typedef vtkSmartPointer<vtkLODActor> PlotLOD; //!< Smart Pointers for Automated Garbage Collection
typedef vtkSmartPointer<vtkCubeAxesActor2D> PlotAxes; //!< Smart Pointers for Automated Garbage Collection
typedef vtkSmartPointer<vtkRenderer> Renderer; //!< Smart Pointers for Automated Garbage Collection
typedef vtkSmartPointer<vtkRenderWindow> RenderWindow; //!< Smart Pointers for Automated Garbage Collection

/*!
    \class DGVSurfacePlotVTK
    \brief This class represents the DGV Surface Plot Display object using VTK.
    \author Shekhar S. Chandra, 2008-2009

    The class displays plot values using OpenGL via the VTK library. The rendering is encapsulated within
    a QVTK widget.
    Controls:
        - Left Mouse (hold): rotate plot.
        - Wheel: zoom the camera.
        - Middle Mouse (hold): translate plot.
        - Right Mouse: context menu and zoom toggle.
        - Keypress f: fly to the picked point.
        - Keypress Shift+r: reset the camera view along the current view direction.
        - Keypress r: reset the zoom to defaults.

    Usage Example:
    \code
    DGVSurfacePlotVTK *plot = new DGVSurfacePlotVTK;

    plot->setName(name);
    plot->setData(data);
    plot->generatePlot();
    plot->generateAxes();
    plot->show();
    \endcode
*/
class DGV_VTK_EXPORT DGVSurfacePlotVTK : public QVTKWidget
{
    Q_OBJECT

public:
    /*!
        \fn DGVSurfacePlotVTK::DGVSurfacePlotVTK(QWidget *parent = 0)
        \brief The standard constructor
    */
    DGVSurfacePlotVTK(QWidget *parent = 0);
    /*!
        \fn DGVSurfacePlotVTK::~DGVSurfacePlotVTK()
        \brief The standard destructor
    */
    virtual ~DGVSurfacePlotVTK();

    /*!
        \fn DGVSurfacePlotVTK::setName(QString filename)
        \brief Set the name of the plot.
    */
    void setName(QString filename);
    /*!
        \fn DGVSurfacePlotVTK::setData(Array<imageType,2> data)
        \brief Set the data to be plotted.
    */
    void setData(Array<imageType,2> data);
    /*!
        \fn DGVSurfacePlotVTK::SetInput(vtkImageData *newData)
        \brief Set the data to be plotted, using VTK syntax.
    */
    void SetInput(vtkImageData *newData);
    /*!
        \fn DGVSurfacePlotVTK::setScaleFactor(double factor)
        \brief Set the scale factor for the surface plot.
    */
    void setScaleFactor(double factor);
    /*!
        \fn DGVSurfacePlotVTK::autoScaleSurface(bool autoScale)
        \brief Auto scale the z-axis corresponding to the surface of the plot?
    */
    inline void autoScaleSurface(bool autoScale)
    {   autoScaleZ = autoScale; }
    /*!
        \fn DGVSurfacePlotVTK::setThresholdLevels(double low, double high)
        \brief Set the thresholding on the data plotted. (To be implemented)
    */
    void setThresholdLevels(double low, double high);
    /*!
        \fn DGVSurfacePlotVTK::setXLabel(QString text)
        \brief Set the label of x-axis.
    */
    void setXLabel(QString text);
    /*!
        \fn DGVSurfacePlotVTK::setYLabel(QString text)
        \brief Set the label of y-axis.
    */
    void setYLabel(QString text);
    /*!
        \fn DGVSurfacePlotVTK::setZLabel(QString text)
        \brief Set the label of z-axis.
    */
    void setZLabel(QString text);
    /*!
        \fn DGVSurfacePlotVTK::setAxesAsClosestTriad()
        \brief Set the axes display method as the closest triad to viewer
    */
    void setAxesAsClosestTriad();
    /*!
        \fn DGVSurfacePlotVTK::setAxesAsClosestTriad()
        \brief Set the axes display method as the outer edges from the viewer
    */
    void setAxesAsOuterEdges();
    /*!
        \fn DGVSurfacePlotVTK::setBackground(double r, double g, double b)
        \brief Sets the background of the renderer to colour (r,g,b).
    */
    void setBackground(double r, double g, double b);
    /*!
        \fn DGVSurfacePlotVTK::saveVTI(const QString filename)
        \brief Saves data using VTK XML Image (VTI) format with stored filename.
    */
	bool saveVTI(const QString filename);

    /*!
        \fn DGVSurfacePlotVTK::generatePlot()
        \brief Generates a surface plot from the data provided.
    */
    void generatePlot();
    /*!
        \fn DGVSurfacePlotVTK::generatePlotMergedWith(vtkImageData *image)
        \brief Generates a surface plot from the data provided and merged with image.
    */
    void generatePlotMergedWith(vtkImageData *image);
    /*!
        \fn DGVSurfacePlotVTK::generateAxes()
        \brief Generates and enables the axes on the plot.
    */
    void generateAxes();
    /*!
        \fn DGVSurfacePlotVTK::animateFromSlices(Array<imageType,3> *data, int interval)
        \brief Animates a surface plot from each slice of a 3D data set.
    */
    void animateFromSlices(Array<imageType,3> *data, int interval);

    /*!
        \fn DGVSurfacePlotVTK::strippedName()
        \brief Returns the stripped (path removed) name of the plot.
    */
    QString strippedName();
    /*!
        \fn DGVSurfacePlotVTK::strippedNamePrefix()
        \brief Returns the stripped (path removed) name of the plot with "SPlot" prefix.
    */
    QString strippedNamePrefix();
    /*!
        \fn DGVSurfacePlotVTK::data()
        \brief Returns the data in Blitz array form.
    */
    inline Array<imageType,2>& data()
    {   return plotArray;   }
    /*!
        \fn DGVSurfacePlotVTK::setConsole(DGVConsole *newConsole)
        \brief Assigns a console for message output.
	*/
	void setConsole(DGVConsole *newConsole);
	/*!
        \fn DGVSurfacePlotVTK::setVerboseMode(bool verbose)
        \brief Verbose mode for message output.
	*/
	inline void setVerboseMode(bool verbose)
	{   verboseMode = verbose;  }

public slots:
    /*!
        \fn DGVSurfacePlotVTK::refresh()
        \brief Reload the data and rest the camera and axes.
    */
    void refresh();
    /*!
        \fn DGVSurfacePlotVTK::renameData()
        \brief Renames the surfaces data.
    */
    void renameData();
    /*!
        \fn DGVSurfacePlotVTK::scale()
        \brief Ask for scale factor
    */
    void scale();
    /*!
        \fn DGVSurfacePlotVTK::threshold()
        \brief Ask for thresholding
    */
    void threshold();
    /*!
        \fn DGVSurfacePlotVTK::thresholdUpper(double value)
        \brief Apply a upper Thresholding
    */
    void thresholdUpper(double value);
    /*!
        \fn DGVSurfacePlotVTK::thresholdLower(double value)
        \brief Apply a lower thresholding
    */
    void thresholdLower(double value);
    /*!
        \fn DGVSurfacePlotVTK::xLabel()
        \brief Ask for x-label
    */
    void xLabel();
    /*!
        \fn DGVSurfacePlotVTK::yLabel()
        \brief Ask for y-label
    */
    void yLabel();
    /*!
        \fn DGVSurfacePlotVTK::zLabel()
        \brief Ask for z-label
    */
    void zLabel();
    /*!
        \fn DGVSurfacePlotVTK::background()
        \brief Ask for rgb values and change background to that colour.
    */
    void background();
    /*!
        \fn DGVSurfacePlotVTK::axesProperties()
        \brief Ask for rgb values and change axes to that colour.
    */
    void axesProperties();
    /*!
        \fn DGVSurfacePlotVTK::toggleLogScale()
        \brief Updates the data to display surface in the desired way (i.e. if log scale etc.).
    */
    void updateDisplayData();
    /*!
        \fn DGVSurfacePlotVTK::toggleAxesAsClosestTriad()
        \brief Toggles if the axes are display with closest triad display mode.
    */
    void toggleAxesAsClosestTriad();
    /*!
        \fn DGVSurfacePlotVTK::toggleAntiAliasing()
        \brief Toggles the Anti-Aliasing in display. May slow rendering if enabled.
    */
    void toggleAntiAliasing();
    /*!
        \fn DGVSurfacePlotVTK::save()
        \brief Saves the data.
    */
    void save();
    /*!
		\fn DGVSurfacePlotVTK::updateSlice()
		\brief Updates slice data, normally triggered by timers for animations.
	*/
	void updateSlice();
	/*!
		\fn DGVSurfacePlotVTK::firstSlice()
		\brief Updates slice count to the first slice.
	*/
	inline void firstSlice()
	{   currentSlice = 0;   }
	/*!
		\fn DGVSurfacePlotVTK::pauseAnimation()
		\brief Pauses and Unpauses animations.
	*/
	void pauseAnimation();

signals:
    /*!
        \fn DGVPlot::nameChanged(const QString newName)
        \brief Send signal that the window has been renamed.
    */
    void nameChanged(const QString newName);

protected:
    bool loaded; //!< Data loaded?
    bool generated; //!< Plot has been generated?
    bool axisGenerated; //!< Axis has been generated?
    bool externalData; //!< External vtkImageData?
    bool verboseMode; //!< Verbose messaging mode
    bool consoleAssigned; //!< Messaging console has been set
    bool closestTriad; //!< Flag for closest triad display of axes
    bool antiAliasing; //!< Smooth Polygons?
    bool thresholded; //!< Thresholded data?
    bool autoScaleZ; //!< Auto Scale the z-axis always?
    bool logScaled; //!< Used log scale? (If so, reset scale)
    bool animating; //!< Animation is happening?
    bool pausedAnimation; //!< Animation is paused?
    QString name; //!< Name of the plot

    ///Context Menu
	QMenu *contextMenu; //!< Context Menu
	QAction *scaleAct; //!< Action object for scaling plot.
	QAction *thresholdAct; //!< Action object for thresholding plot.
	//------------------
	QAction *xLabelAct; //!< Change x label
	QAction *yLabelAct; //!< Change y label
	QAction *zLabelAct; //!< Change z label
	QAction *backgroundAct; //!< Change background colour?
	QAction *axesAct; //!< Change axes colour?
	QAction *logAct; //!< Show logscale?
	QAction *triadAct; //!< Show triad axes?
	QAction *antiAliasingAct; //!< Change Anti Aliasing
    //------------------
    QAction *startAct; //!< Start Animation for 3D datasets
    QAction *pauseAct; //!< Pause Animation for 3D datasets
    //------------------
    QAction *saveAct; //!< Saves data as VTI file
    QAction *refreshAct; //!< Refreshes window
    QAction *renameAct; //!< Renames window
	QAction *closeAct; //!< Closes window

    int bounds[6]; //!< Bounds of the data
    double scaling; //!< Scaling factor
    PlotData plotData; //!< Actual data stored as using an image geometry, Smart Pointer
    DGVBlitzArrayCasterVTK<imageType> Blitz; //!< For casting Blitz arrays to and from VTK structures
    Array<imageType,2> plotArray; //!< Plot data in array form.
    Array<imageType,3> *volumeData; //!< Pointer to volume array, used for animations
    int currentSlice; //!< Slice being showm

    DGVConsole *console; //!< Console for message output
    ThresholdForm *thresholder; //!< Threshold form

    PlotLogScale logData; //!< For log scaling
    PlotGeometry geometry; //!< Used to create the geometry for a surface plot, Smart Pointer
    PlotWarp warp; //!< Surface quantifier, Smart Pointer
    PlotNorms surfaceNormals; //!< Normals for the mesh, Smart Pointer
    PlotMapper mapper; //!< Map the data to the surface, Smart Pointer
    PlotLOD lod; //!< Level of Detail adjuster, Smart Pointer
    PlotAxes axes; //!< Axis for plot
    Renderer renderer; //!< Renderer of the plot
    RenderWindow renderWin; //!< Window that controls the renderer

    /*!
		\fn DGVSurfacePlotVTK::setupEvents()
		\brief Executes common events setup code.
	*/
	void setupEvents();
	/*!
		\fn DGVSurfacePlotVTK::setupSurface()
		\brief Executes common code for setting up the surface in VTK.
	*/
	void setupSurface();
	/*!
		\fn DGVSurfacePlotVTK::contextMenuEvent(QContextMenuEvent *event)
		\brief The context menu setup member
	*/
	void contextMenuEvent(QContextMenuEvent *event);
    /*!
        \fn DGVSurfacePlotVTK::printError(QString msg)
        \brief Error message wrapper for console.
	*/
	void printError(QString msg);
	/*!
        \fn DGVSurfacePlotVTK::printWarning(QString msg)
        \brief Warning message wrapper for console.
	*/
	void printWarning(QString msg);
	/*!
        \fn DGVSurfacePlotVTK::printInfo(QString msg)
        \brief Info message wrapper for console.
	*/
	void printInfo(QString msg);
	/*!
		\fn DGVSurfacePlotVTK::createActions()
		\brief Create actions for internal use.
	*/
	void createActions();
	/*!
		\fn DGVSurfacePlotVTK::createConnections()
		\brief Create connections for internal use.
	*/
	void createConnections();
};

#endif // DGVSURFACEPLOTVTK_H
